package com.iwechat.controller;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.WebApplicationContext;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.iwechat.emuns.ConstEmus;
import com.iwechat.mybatis.generator.model.TemplateMessage;
import com.iwechat.service.ClientFactory;
import com.iwechat.service.MessageHandlerFactory;
import com.iwechat.service.TempMsgPriorityQueue;
import com.iwechat.util.StringUtil;

/**
 * Handles requests for template message.
 */
@Controller
@RequestMapping("/tm")
public class TemplateMessageController {

    private static final Logger   logger                       = LogManager.getLogger();
    public static final int       ERROR_TEMPMESG_INVAID_DATA   = -3;
    public static final int       ERROR_TEMPMESG_INVAID_IP     = -2;
    public static final int       ERROR_TEMPMESG_INVAID_ID     = -1;
    public static final int       SUCCESS                      = 0;
    public static final int       ERROR_TEMPMESG_SEND_TOO_FAST = 1;
    public static final int       ERROR_TEMPMESG_CANT_PREPARE  = 2;
    public static final int       ERROR_SAVE2DB                = -1001;
    public static final int       ERROR_SEND2WX_EMPTY_RESP     = -1002;

    @Autowired
    private WebApplicationContext wac;

    @Resource(name = "RedisPriorityQuenue")
    TempMsgPriorityQueue        queue;

    private Map<String, Integer>  recvWin                      = new ConcurrentHashMap<String, Integer>();

    /**
     * 单条模板消息发送
     */
    @RequestMapping(value = "/single", method = { RequestMethod.GET, RequestMethod.POST })
    public void singleMessage(HttpServletRequest request, HttpServletResponse response) {
        JSONObject requestJson = null;
        try {
            InputStream inStream = null;
            inStream = request.getInputStream();
            response.setCharacterEncoding(request.getCharacterEncoding());
            String query = IOUtils.toString(inStream, request.getCharacterEncoding());
            logger.info("recive singleMessage: " + query);
            requestJson = JSON.parseObject(query);

            // 获取客户端api设置的ip
            String clientIp = requestJson.getString(ConstEmus.clientIp.value());
            // 获取消息发送者
            String clientId = requestJson.getString(ConstEmus.clientId.value());

            boolean chkip = clientIpFilter(clientIp);
            if (!chkip) {
                responseJson(response, ERROR_TEMPMESG_INVAID_IP, requestJson);
                return;
            }
            int chkid = clientIdFilter(clientId);
            if (chkid != 0) {
                responseJson(response, chkid, requestJson);
                return;
            }

            requestJson.put(ConstEmus.sessionId.value(), request.getSession().getId());
            int errCd = handleSingle(requestJson);
            responseJson(response, errCd, requestJson);

        } catch (Exception e) {
            logger.error(e, e);
            responseJson(response, ERROR_TEMPMESG_INVAID_DATA, requestJson);
        }
    }

    @RequestMapping(value = "/monitor", method = RequestMethod.GET)
    public void monitor(HttpServletRequest request, HttpServletResponse response) {
        // 发送响应
        try {
            response.setCharacterEncoding(response.getCharacterEncoding());
            response.setContentType("text/html;charset=" + response.getCharacterEncoding());
            PrintWriter write = response.getWriter();
            write.println(StringUtil.toHtml(queue.monitor()));
        } catch (IOException e) {
            logger.error(e, e);
        }
    }

    /**
     * 处理单条模板消息
     *
     *
     * @param requestJson
     * @return
     */
    private int handleSingle(JSONObject requestJson) {
        int ret = 0;
        MessageHandlerFactory mf = wac.getBean(MessageHandlerFactory.class);
        // 上送消息进行模板预处理
        TemplateMessage message = mf.prepare(requestJson);
        if (message == null) {
            ret = ERROR_TEMPMESG_CANT_PREPARE;
        } else {
            // 模板消息处理
            ret = mf.doHandle(message);
        }
        return ret;
    }

    private void responseJson(HttpServletResponse response, int retCode, JSONObject requestJson) {
        JSONObject ret = new JSONObject();
        if (requestJson == null) {
            requestJson = new JSONObject();
        }
        ret.put(ConstEmus.sequence.value(), requestJson.getString(ConstEmus.sequence.value()));
        ret.put(ConstEmus.errorCode.value(), retCode);
        switch (retCode) {
        case ERROR_TEMPMESG_INVAID_DATA:
            ret.put(ConstEmus.errorMesg.value(), "客户端发送数据有误");
        break;
        case ERROR_TEMPMESG_INVAID_IP:
            ret.put(ConstEmus.errorMesg.value(), "客户端ip不在白名单中");
        break;
        case ERROR_TEMPMESG_INVAID_ID:
            ret.put(ConstEmus.errorMesg.value(), "客户端clientId无效");
        break;
        case SUCCESS:
            ret.put(ConstEmus.errorMesg.value(), "success");
        break;
        case ERROR_TEMPMESG_SEND_TOO_FAST:
            ret.put(ConstEmus.errorMesg.value(), "发送过快");
        break;
        case ERROR_TEMPMESG_CANT_PREPARE:
            ret.put(ConstEmus.errorMesg.value(), "消息预处理错误,可能是模板id不正确");
        break;
        case ERROR_SAVE2DB:
            ret.put(ConstEmus.errorMesg.value(), "消息存储数据库异常");
        break;
        case ERROR_SEND2WX_EMPTY_RESP:
            ret.put(ConstEmus.errorMesg.value(), "消息发送至第三方异常");
        break;
        default:
            ret.put(ConstEmus.errorMesg.value(), "unknown");
        break;
        }

        // 处理窗口
        Integer current = recvWin.get(requestJson.getString(ConstEmus.clientId.value()));
        if (current != null) {
            current--;
            if (current < 0) {
                current = 0;
            }
            recvWin.put(requestJson.getString(ConstEmus.clientId.value()), current);
        }
        // 发送响应
        try {
            response.setCharacterEncoding(response.getCharacterEncoding());
            response.setContentType("text/json;charset=" + response.getCharacterEncoding());
            PrintWriter write = response.getWriter();
            String s = ret.toJSONString();
            logger.info("response singleMessage : " + s);
            write.println(s);
        } catch (IOException e) {
            logger.error(e, e);
        }
    }

    /**
     * 检查当前clientIp是否在白名单中
     *
     *
     * @param clientIp
     * @return
     */
    private boolean clientIpFilter(String clientIp) {
        ClientFactory cf = wac.getBean(ClientFactory.class);
        return cf.checkIP(clientIp);
    }

    /**
     * 检查当前clientId是否可以继续发送消息
     *
     *
     * @param clientId
     * @return -1 : clientId无效<br>
     *         0 : 正常<br>
     *         1 : 发送过快<br>
     */
    private int clientIdFilter(String clientId) {
        ClientFactory cf = wac.getBean(ClientFactory.class);
        int max = cf.getWindowByClientId(clientId);
        Integer current = recvWin.get("clientId");
        if (max > 0) {
            if (current == null || current.intValue() <= 0) {
                recvWin.put(clientId, 1);
                return SUCCESS;
            } else {
                if (current.intValue() < max) {
                    current++;
                    recvWin.put(clientId, current);
                    return SUCCESS;
                } else {
                    return ERROR_TEMPMESG_SEND_TOO_FAST;
                }

            }
        } else {
            return ERROR_TEMPMESG_INVAID_ID;
        }
    }
}
